package com.ljx.visitorMode;

/**
 *
 * 双分派（访问者模式用到了一种双分派的技术）
 *
 * 根据对象的类型而对方法进行的选择，就是分派(Dispatch)，分派(Dispatch)又分为两种，即静态分派和动态分派
 *
 * **静态分派(Static Dispatch)** 发生在编译时期，分派根据静态类型信息发生。
 * 静态分派对于我们来说并不陌生，方法重载就是静态分派。
 *
 * **动态分派(Dynamic Dispatch)** 发生在运行时期，动态分派动态地置换掉某个方法。
 * Java通过方法的重写支持动态分派。
 *
 * **双分派(Double Dispatch)**
 * 所谓双分派技术就是在选择一个方法的时候，不仅仅要根据消息接收者（receiver）的运行时区别，还要根据参数的运行时区别
 *
 * @作者 LJX
 * @日期 2022/12/26 16:51
 */
public class DoubleAssignment {

    public static void main(String[] args) {
        //测试动态分派（Java编译器在编译时期并不总是知道哪些代码会被执行，因为编译器仅仅知道对象的静态类型，而不知道对象的真实类型；而方法的调用则是根据对象的真实类型，而不是静态类）
        System.out.println("===============测试动态分派==============");
        AnimalDynamicDispatch add1 = new DogDynamicDispatch();
        add1.execute();
        AnimalDynamicDispatch add2 = new CatDynamicDispatch();
        add2.execute();

        //测试静态分派（重载方法的分派是根据静态类型进行的，这个分派过程在编译时期就完成了）
        System.out.println("===============测试静态分派==============");
        AnimalStaticDispatch asd1 = new AnimalStaticDispatch();
        AnimalStaticDispatch asd2 = new DogStaticDispatch();
        AnimalStaticDispatch asd3 = new CatStaticDispatch();

        ExecuteStaticDispatch exe = new ExecuteStaticDispatch();
        exe.execute(asd1);
        exe.execute(asd2);
        exe.execute(asd3);

        //测试双分派（双分派实现动态绑定的本质，就是在重载方法委派的前面加上了继承体系中覆盖的环节，由于覆盖是动态的，所以重载就是动态的了）
        System.out.println("===============测试双分派==============");
        AnimalDoubleAssignment ada1 = new AnimalDoubleAssignment();
        AnimalDoubleAssignment ada2 = new DogDoubleAssignment();
        AnimalDoubleAssignment ada3 = new CatDoubleAssignment();

        ExecuteDoubleAssignment executeDoubleAssignment = new ExecuteDoubleAssignment();
        ada1.accept(executeDoubleAssignment);
        ada2.accept(executeDoubleAssignment);
        ada3.accept(executeDoubleAssignment);

    }

}

/**
 * 动态分派动物类
 */
class AnimalDynamicDispatch {
    public void execute() {
        System.out.println("Animal");
    }
}

class DogDynamicDispatch extends AnimalDynamicDispatch {
    @Override
    public void execute() {
        System.out.println("DogDynamicDispatch");
    }
}

class CatDynamicDispatch extends AnimalDynamicDispatch {
    @Override
    public void execute() {
        System.out.println("CatDynamicDispatch");
    }
}

/**
 * 静态分派动物类
 */
class AnimalStaticDispatch{
}

class DogStaticDispatch extends AnimalStaticDispatch{
}

class CatStaticDispatch extends AnimalStaticDispatch{

}

/**
 * 静态分派执行类
 */
class ExecuteStaticDispatch {
    public void execute(AnimalStaticDispatch a) {
        System.out.println("AnimalStaticDispatch");
    }

    public void execute(DogStaticDispatch d) {
        System.out.println("DogStaticDispatch");
    }

    public void execute(CatStaticDispatch c) {
        System.out.println("CatStaticDispatch");
    }
}

/**
 * 双分派动物类
 */
class AnimalDoubleAssignment{
    public void accept(ExecuteDoubleAssignment executeDoubleAssignment){
        executeDoubleAssignment.execute(this);
    }
}

class DogDoubleAssignment extends AnimalDoubleAssignment{
    public void accept(ExecuteDoubleAssignment executeDoubleAssignment){
        executeDoubleAssignment.execute(this);
    }
}

class CatDoubleAssignment extends AnimalDoubleAssignment{
    public void accept(ExecuteDoubleAssignment executeDoubleAssignment){
        executeDoubleAssignment.execute(this);
    }
}

/**
 * 双分派执行类
 */
class ExecuteDoubleAssignment{

    public void execute(AnimalDoubleAssignment animalDoubleAssignment) {
        System.out.println("AnimalDoubleAssignment");
    }
    public void execute(DogDoubleAssignment dogDoubleAssignment) {
        System.out.println("DogDoubleAssignment");
    }
    public void execute(CatDoubleAssignment catDoubleAssignment) {
        System.out.println("CatDoubleAssignment");
    }
}
